#include "lib.h"
#include "sltsql.h"
#include "progsql.h"
#include "slotopts.h"
#include "odbc.h"
#include "opts.h"
#include "slotspin.h"
#include "missinggamenums.h"

#include <memory>
typedef std::auto_ptr<ODBCConnection> autoDeleteConn;

SlotsSQL::SlotsSQL(const String& DBDSN, const String& DBLogin, const String& DBPassword)
	: ProgressiveTrackSQL(DBDSN, DBLogin, DBPassword)
{
#ifdef USE_MISSINGGAMENUMS
	//missing game nums deleted in TrackSQL::~TrackSQL
	missinggamenums = new MissingGameNums(this, "pub_getTableIdentitySlots");
#endif
}


int32
SlotsSQL::getSubGameData(SubGame *subGame)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
    int32 rc = ExecFailed;

	conn = getConn();
	if (conn)
    {
        query = conn->query();
        if (query)
        {
            query->define("exec pub_AUSlotsGetSubGameData ");
            query->addParam(subGame->getMachid(), ODBCQuery::BINARY);
            query->addParam(subGame->getPid());
            query->addParam(subGame->getCreditValue());
            query->addParam((bool8)(subGame->isForMoney() != 0));
    
            if (query->exec())
            {
                uint8 id;
                int64 data;
                bool8 serverOnly;
                ok = true;
				while ( ok && query->getRow() )
				{
                    ok = query->getData(1, &id);
                    if ( ok )
                    {
                        ok = query->getData(2, &data);
                    }
                    else
                    {
                        /**
                         * Problem with Id.
                         */
                        ASSERT(0);
                    }

                    if ( ok )
                    {
                        ok = query->getData(3, &serverOnly);
                    }
                    else
                    {
                        /**
                         * Problem with Data.
                         */
                        ASSERT(0);
                    }


                    if ( ok )
                    {
						subGame->setServerOnly(id, serverOnly);
						subGame->update(id, data);
                    }
                    else
                    {
                        /**
                         * Problem with serverOnly.
                         */
                        rc = ExecFailed;
                    }

                }
            }
            delete query;
        }
        else
        {
            rc = NoConnection;
        }
    	delete conn;
    }
    else
    {
		rc = NoConnection;
    }

    return rc;

}



int32
SlotsSQL::setSubGameData(SubGame *subGame)
{
	
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;	

	// CSN-13475: new procedure with a table parameter
	//				We need to build a little script to be able to run it
	String sQuery = "BEGIN \n";
	sQuery = sQuery + "SET NOCOUNT ON; \n";
	sQuery = sQuery + "DECLARE @AUSlotsSubGameData_param [dbo].[udt_AUSlotsSubGameData]; \n";
	sQuery = sQuery + "INSERT @AUSlotsSubGameData_param ([machId],[pid],[machsubid],[formoney],[subgameid],[subgamedata],[subgameserveronly]) VALUES \n";
	
	uint8 nDataCount = subGame->getDataCount() - 1;
	uint8 iIndex = 0;
	String sRow;

	while(iIndex < nDataCount)
	{
		// All rows except last one (,)
		sRow.sprintf(TEXT("(%u, '%s', %d, %u, %d, %I64d, %u),\n"), subGame->getMachid(), (const uint16*)subGame->getPid(), subGame->getCreditValue(), subGame->isForMoney(), 
																   subGame->getIdAt(iIndex), subGame->getDataAt(iIndex), subGame->isServerOnlyAt(iIndex));
		sQuery = sQuery + sRow;
		iIndex++;
	}
	// Last row (;)
	sRow.sprintf(TEXT("(%u, '%s', %d, %u, %d, %I64d, %u);\n"), subGame->getMachid(), (const uint16*)subGame->getPid(), subGame->getCreditValue(), subGame->isForMoney(), 
															   subGame->getIdAt(iIndex), subGame->getDataAt(iIndex), subGame->isServerOnlyAt(iIndex));
	sQuery = sQuery + sRow;

	sQuery = sQuery + "EXEC [dbo].[pub_AUSlotsSetSubGameDataAll] @AUSlotsSubGameData = @AUSlotsSubGameData_param;\n";
	sQuery = sQuery + "END";

	conn = getConn();
	if (conn)
	{
		query = conn->query();		
		if (query)
		{
			query->define(sQuery);	
			ok = query->exec();
			if (!ok)
			{
				/**
				* Unable to execute query.
				*/
				ASSERT(0);
			}
			delete query;
		}
		else
		{
			/**
			* Couldn't get query
			*/
			ASSERT(0);
		}				

		delete conn;	// CSN-14354
	}

    return ok;
}

int32
SlotsSQL::archiveSubGameData(int64 gamenum, SubGame *subGame)

{
	ODBCConnection* conn;
	ODBCQuery* query;
    int32 rc = ExecFailed;

	conn = getConn();
	if (conn)
    {
        rc = NoError;
        for ( int i = 0; rc == NoError && i < subGame->getDataCount() && gamenum > 0; i++ )
        {
            query = conn->query();
            if (query)
            {
                query->define("exec pub_SlotsArchiveSubGameData ");
                query->addParam(gamenum);
                query->addParam(subGame->getIdAt(i));
                query->addParam(subGame->getDataAt(i));

                if (query->exec())
                {
                    rc = NoError;
                }
                else
                {
                    /**
                     * Unable to execute query.
                     */
                    rc = ExecFailed;
                }
                delete query;
            }
            else
            {
                rc = NoConnection;
            }
        }
    	delete conn;
    }
    else
    {
		rc = NoConnection;
    }

    return rc;

}

int32
SlotsSQL::getFeatureData(Feature *feature)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
    int32 rc = ExecFailed;

	conn = getConn();
	if (conn)
    {
        query = conn->query();
        if (query)
        {
            query->define("exec pub_AUSlotsGetFeatureData ");
            query->addParam(feature->getGameNum());
            if (query->exec())
            {
				uint8 level;
                uint8 id;
                int32 data;
                bool8 serverOnly;
                ok = true;
				while ( ok && query->getRow() )
				{
					ok = query->getData(1, &level);
					if (ok)
					{
	                    ok = query->getData(2, &id);
					}
					else
					{
                        /**
                         * Problem with level.
                         */
                        ASSERT(0);

					}
                    if ( ok )
                    {
                        ok = query->getData(3, &data);
                    }
                    else
                    {
                        /**
                         * Problem with Id.
                         */
                        ASSERT(0);
                    }

                    if ( ok )
                    {
                        ok = query->getData(4, &serverOnly);
                    }
                    else
                    {
                        /**
                         * Problem with Data.
                         */
                        ASSERT(0);
                    }


                    if ( ok )
                    {
                        feature->updateLevel(level, id, data, serverOnly);
                    }
                    else
                    {
                        /**
                         * Problem with serverOnly.
                         */
                        rc = ExecFailed;
                    }

                }
            }
            delete query;
        }
        else
        {
            rc = NoConnection;
        }
    	delete conn;
    }
    else
    {
		rc = NoConnection;
    }

    return rc;

}

int32
SlotsSQL::setFeatureData(Feature *feature)
{
	ODBCConnection* conn;
	ODBCQuery* query;	
	int32 rc = ExecFailed;

	// CSN-14254: new procedure with a table parameter
	//				We need to build a little script to be able to run it
	String sQuery = "BEGIN \n";
	sQuery = sQuery + "SET NOCOUNT ON; \n";
	sQuery = sQuery + "DECLARE @AUSlotsFeatureData_param [udt_AUSlotsFeatureData]; \n";
	sQuery = sQuery + "INSERT @AUSlotsFeatureData_param (gamenum, featurelevel, featureid, featuredata, serveronly) VALUES \n";
	
	uint8 nNumLevels = feature->getLevelCount();
	
	for (uint8 i = 0; i < nNumLevels; i++)
    {
		// For each level loop through each data record
		uint8 level = feature->getLevelAt(i);
		uint8 nNumFeatures = feature->getDataCountLevel(level);

		for (int j = 0; j < nNumFeatures; j++)
        {			
			String sRow;			
			sRow.sprintf(TEXT("(%I64d, %u, %d, %d, %u)"), 
						feature->getGameNum(), level, feature->getIdAtLevel(level, j), feature->getDataAtLevel(level, j), feature->isServerOnlyAtLevel(level, j));
		
			if ((i == nNumLevels-1) && (j == nNumFeatures-1))
				sRow = sRow + TEXT(";\n");
			else
				sRow = sRow + TEXT(",\n");

			sQuery = sQuery + sRow;
		}
	}
	sQuery = sQuery + "EXEC dbo.pub_AUSlotsSetFeatureDataAll @AUSlotsFeatureData_param;\n";
	sQuery = sQuery + "END";

	conn = getConn();
	if (conn)
	{
		query = conn->query();		
		if (query)
		{
			query->define(sQuery);	
			if (query->exec())
			{
				rc = NoError;			
			}
			delete query;
		}
		else
		{
			/**
			* Couldn't get query
			*/			
			rc = NoConnection;
		}				

		delete conn;
	}

    return rc;
}

bool8 
SlotsSQL::createBonusGame( SlotGuts *guts, int64 gamenum, uint8 bonusgametype, uint8 bonusgameindex, int32 basepayoutamount, int32 totalmultiplier, int32 totalbonuspayoutamount, int32 freespins)
{	
	return createBonusGame( guts, gamenum, bonusgametype, 
									bonusgameindex, basepayoutamount, totalmultiplier, 
									totalbonuspayoutamount, freespins, 
									autoDeleteConn( getConn() ).get() );
}

bool8 
SlotsSQL::createBonusGame( SlotGuts *guts, int64 gamenum, uint8 bonusgametype, uint8 bonusgameindex, int32 basepayoutamount, int32 totalmultiplier, int32 totalbonuspayoutamount, int32 freespins, ODBCConnection* conn)
{
	ODBCQuery* query;
	bool8 ok = false;

	if (conn)
    {
        query = conn->query();
        if (query)
        {
            query->define("exec pub_AUSlotsCreateBonusGame ");
            query->addParam(gamenum);
            query->addParam(guts->getInfo()->pid);
			query->addParam(guts->getMachId(), ODBCQuery::BINARY);
            query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);
            query->addParam((bool8)(guts->isForMoney() != 0));
            query->addParam(bonusgametype);
            query->addParam(bonusgameindex);
			query->addParam(basepayoutamount,ODBCQuery::MONEY);
			query->addParam(totalmultiplier);
			query->addParam(totalbonuspayoutamount,ODBCQuery::MONEY);
			query->addParam(freespins);
                
            if (query->exec())
            {
                ok = true;
            }

            delete query;
        }
    }

    return ok;
}

bool8
SlotsSQL::getGutsName(int32 gutsId, char* name)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec pub_AUSlotsGetGutName ");
		query->addParam(gutsId);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok = query->getData(1, name,64);

                if ( !ok )
                {
                    /**
                     * Unable to get Name.
                     */
                    ASSERT(0);
                    break;
                }

			}
		}
		delete query;
	}
	delete conn;

	return ok;
}




int32
SlotsSQL::getPlayerLimits(const PID& pid, int32 gameId, uint8 machId,
	int32* compFactor)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec pub_lim_getPlayerLimits ");
		query->addParam(pid);
		query->addParam(gameId);
		query->addParam(machId, ODBCQuery::BINARY);

		if (query->exec())
		{
			while (query->getRow())
			{
				ok = query->getData(4, compFactor);

                if ( !ok )
                {
                    /**
                     * Unable to get compFactor.
                     */
                    ASSERT(0);
                    break;
                }

			}
		}
		delete query;
	}
	delete conn;

    if (!ok)
    {
        compFactor = 0;
    }

	return ok ? isGameEnabled(gameId,machId) : ExecFailed;
}


bool8
SlotsSQL::createWheels(SlotSpin *spin, ODBCConnection* conn)
{
	ODBCQuery* query;
	bool8 ok = false;	

	// CSN-13472: new procedure with a table parameter
	//			  We need to build a little script to be able to run it
	String sQuery = "BEGIN \n";
	sQuery = sQuery + "SET NOCOUNT ON; \n";
	sQuery = sQuery + "DECLARE @AUSlotsWheelStops_param [dbo].[udt_AUSlotsWheelStops]; \n";
	sQuery = sQuery + "INSERT @AUSlotsWheelStops_param([gamenum],[wheelnum],[wheelstop]) VALUES \n";
	
	uint8 nDataCount = spin->getStopCount() - 1;
	uint8 reelidx = 0;
	String sRow;

	while(reelidx < nDataCount)
	{
		// All rows except last one (,)
		sRow.sprintf(TEXT("(%I64d, %u, %u),\n"), spin->getGameNum(), reelidx, spin->getStops()[reelidx]);
		sQuery = sQuery + sRow;
		reelidx++;
	}
	// Last row (;)
	sRow.sprintf(TEXT("(%I64d, %u, %u);\n"), spin->getGameNum(), reelidx, spin->getStops()[reelidx]);
	sQuery = sQuery + sRow;

	sQuery = sQuery + "EXEC [dbo].[pub_AUSlotsCreateWheelStopsAll] @AUSlotsWheelStops = @AUSlotsWheelStops_param;\n";
	sQuery = sQuery + "END";

	query = conn->query();		
	if (query)
	{
		query->define(sQuery);	
		ok = query->exec();
		if (!ok)
		{
			/**
			* Unable to execute query.
			*/
			ASSERT(0);
		}
		delete query;
	}
	else
	{
		/**
		* Couldn't get query
		*/
		ASSERT(0);
	}				
	
    return ok;
}

bool8
SlotsSQL::createWheelView(SlotSpin *spin, ODBCConnection* conn)
{
	ODBCQuery* query;
	bool8 ok = false;	

	// CSN-13470: new procedure with a table parameter
	//				We need to build a little script to be able to run it
	String sQuery = "BEGIN \n";
	sQuery = sQuery + "SET NOCOUNT ON; \n";
	sQuery = sQuery + "DECLARE @AUSlotsWheelViews [udt_AUSlotsWheelView]; \n";
	sQuery = sQuery + "INSERT @AUSlotsWheelViews (gamenum, wheelnum, offsetFromTopOfWheel, iconid) VALUES \n";
	uint8 nNumRows = spin->getNumRows();
	uint8 nNumCols = spin->getStopCount();
	for (uint8 reelidx = 0; reelidx < nNumCols; reelidx++)
    {
		for (uint8 rowidx = 0; rowidx < nNumRows; rowidx++)
        {
			uint8 icon = spin->getWheelViewIcon(reelidx,rowidx);
			
			String sRow;			
			sRow.sprintf(TEXT("(%I64d, %u, %u, %u)"), spin->getGameNum(), reelidx, rowidx, icon);
		
			if ((reelidx == nNumCols-1) && (rowidx == nNumRows-1))
				sRow = sRow + TEXT(";\n");
			else
				sRow = sRow + TEXT(",\n");

			sQuery = sQuery + sRow;
		}
	}
	sQuery = sQuery + "EXEC dbo.pub_AUSlotsCreateWheelViews @AUSlotsWheelViews;\n";
	sQuery = sQuery + "END";

	query = conn->query();	
	if (query)
	{
		query->define(sQuery);	
		ok = query->exec();
		if (!ok)
		{
			/**
			* Unable to execute query.
			*/
			ASSERT(0);
		}
		delete query;
	}
	else
	{
		/**
		* Couldn't get query
		*/
		ASSERT(0);
	}				

    return ok;
}

int32 
SlotsSQL::createWin(int32 casinoId, 
                    const PID& pid,
                    bool8 forMoney,
                    int32 compFactor,
                    int64 gamenum,
                    uint8 lineid,
                    uint8 payouttypeid,
                    int32 basepayoutamount,
                    int32 totalmultiplier,
                    int32 totallinepayoutamount,
                    int32 *balance,
                    bool8 jackpot,
					ODBCConnection* conn)
{
	ODBCQuery* query;
	bool8 ok = false;

	if (conn)
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_AUSlotsCreateLineResults ");
            query->addParam(casinoId);
            query->addParam(pid);
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam((bool8)(forMoney != 0));
            query->addParam(lineid);
            query->addParam(payouttypeid);
            query->addParam(basepayoutamount, ODBCQuery::MONEY);
            query->addParam((int32)totalmultiplier);
            query->addParam(totallinepayoutamount, ODBCQuery::MONEY);
            query->addParam(jackpot);
            
            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Bad exec of pub_AUSlotsCreateLineResults.
                 */
                ASSERT(0);
            }
            delete query;
        }
        else
        {
            /**
             * Bad query.
             */
            ASSERT(0);
        }
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }

    return ok;
}

int32 
SlotsSQL::createLineResultNote(int64 gamenum,
                               uint8 lineid,
                               uint8 noteid,
							   ODBCConnection* conn)
{
	ODBCQuery* query;
	bool8 ok = false;

	if (conn)
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_AUSlotsCreateLineResultsNotes ");
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam(lineid);
            query->addParam(noteid);
            
            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Bad exec of pub_AUSlotsCreateLineResultsNotes.
                 */
                ASSERT(0);
            }
            delete query;
        }
        else
        {
            /**
             * Bad query.
             */
            ASSERT(0);
        }
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }

    return ok;
}

int32 
SlotsSQL::createScatterResultNote(int64 gamenum,
                                  uint8 payouttypeid,
                                  uint8 noteid,
								  ODBCConnection* conn)
{
	ODBCQuery* query;
	bool8 ok = false;

	if (conn)
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_AUSlotsCreateScatterResultsNotes ");
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam(payouttypeid);
            query->addParam(noteid);
            
            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Bad exec of pub_AUSlotsCreateScatterResultsNotes.
                 */
                ASSERT(0);
            }
            delete query;
        }
        else
        {
            /**
             * Bad query.
             */
            ASSERT(0);
        }
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }

    return ok;
}
int32 
SlotsSQL::createBonusResultNote(int64 gamenum,
                               uint8 lineid,
                               uint8 noteid,
							   ODBCConnection* conn)
{
	ODBCQuery* query;
	bool8 ok = false;

	if (conn)
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_AUSlotsCreateBonusResultsNotes ");
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam(lineid);
            query->addParam(noteid);
            
            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Bad exec of pub_AUSlotsCreateBonusResultsNotes.
                 */
                ASSERT(0);
            }
            delete query;
        }
        else
        {
            /**
             * Bad query.
             */
            ASSERT(0);
        }
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }

    return ok;
}
int32 
SlotsSQL::createScatterResults( int64 gamenum, 
                                uint8 scatterid,
                                int32 scatterpos, 
                     	        uint8 payouttypeid, 
                                int32 basepayoutamount,
                                int32 totalmultiplier,
                                int32 totalscatterpayoutamount,
                     	        bool8 jackpot,
                                int32 freespins,
								ODBCConnection* conn )

{
	ODBCQuery* query;
	bool8 ok = false;
	if (conn)
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_AUSlotsCreateScatterResults ");
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam(scatterid);
            query->addParam(scatterpos);
            query->addParam(payouttypeid);
            query->addParam(basepayoutamount, ODBCQuery::MONEY);
            query->addParam(totalmultiplier);
            query->addParam(totalscatterpayoutamount, ODBCQuery::MONEY);
            query->addParam(jackpot);
            query->addParam(freespins);
            
            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Bad exec of createScatterResults.
                 */
                ASSERT(0);
            }
            delete query;
        }
        else
        {
            /**
             * Bad query.
             */
            ASSERT(0);
        }
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }

    return ok;
}
		
int32 
SlotsSQL::saveSpins(int32 casinoId, SlotGuts *guts)
{
    SlotSpin *spin;
	bool8 ok = true;

	//FB Case 16437 - Use just one connection for everything this method does.
	autoDeleteConn deleteMe( getConn() );
	ODBCConnection* conn = deleteMe.get();
	if ( !conn )
		return false;

	spin = guts->getSlotSpin();

    if ( spin->isSpinComplete() && !spin->isSpinSaved() )
    {
        
		
		/**
         * Save the wins.
         */
		// CSN-13472 - Rewrite additional AU Slots SPs to use a table-valued parameter
		ok = saveWins(spin, conn);
        
        if ( ok )
        {
            ok = createWheels(spin, conn);
        }
        else
        {
            /**
             * unable to create win.
             */
            ASSERT(0);
        }

        if ( ok )
        {
            createWheelView(spin, conn);
        }

        if ( ok )
        {
			// CSN-14253 - Rewrite additional AU Slots SPs to use a table-valued parameter
			ok = saveScatters(spin, conn);

        }
        else
        {
            // Unable to create wheels
			ASSERT(false);
        }

        if ( ok )
        {
            if ( saveBonusGames(guts, conn) != SlotsSQL::NoError )
			{
				ok = false;
			}
        }
        else
        {
            // Unable to create scatters.
			ASSERT(false);
        }

        if ( ok )
        {
            spin->setSpinSaved(true);
        }
        else
        {
            // Unable to save bonus games.
			ASSERT(false);
        }

    }

    if ( !ok )
    {
        /**
         * unable to save spin
         */
        ASSERT(0);
    }

	return ok ? NoError : ExecFailed;

}

bool8
SlotsSQL::saveWins(SlotSpin *spin, ODBCConnection *conn)
{
	ODBCQuery* query;
	bool8 ok = true;

	// CSN-13472 - Rewrite additional AU Slots SPs to use a table-valued parameter
	// We have to create two scripts here:
	// 1) Create Line results (sQueryLines)
	// 2) Create Line results notes (sQueryNotes)
	
	String sQueryLines;
	String sQueryNotes;
		
	String sQueryLinesRows;
	String sQueryNotesRows;
	String sRow;

	bool8 bSomeLine = false;
	bool8 bSomeNote = false;
	for ( uint8 lineidx = 0; lineidx < spin->getSpinLineCount(); lineidx++ )
	{
		const SpinLine *spinLine = spin->getSpinLineAt(lineidx);
	
		if (spinLine->totallinepayoutamount>0 || spinLine->jackpot)
		{
			if (bSomeLine)
				sQueryLinesRows = sQueryLinesRows + String(",");
				
			sRow.sprintf(TEXT("(%I64d,%u,%u,CAST(%d/100.00 as MONEY),%u,%d,CAST(%d/100.00 as MONEY))\n"), 
						spin->getGameNum(), spinLine->lineid, spinLine->payouttypeid, spinLine->basepayoutamount, spinLine->jackpot, spinLine->totalmultiplier, spinLine->totallinepayoutamount); 
							
			sQueryLinesRows = sQueryLinesRows + sRow;
			bSomeLine = true;
		}
				
		for ( uint8 noteidx = 0; noteidx < spinLine->getNoteCount(); noteidx++ )
        {
			if (bSomeNote)
				sQueryNotesRows = sQueryNotesRows + String(",");
				
			sRow.sprintf(TEXT("(%I64d,%u,%u)\n"), spin->getGameNum(), spinLine->lineid, spinLine->getNote(noteidx));

			sQueryNotesRows = sQueryNotesRows + sRow;
			bSomeNote = true;
		}
		
	}
	
	if (bSomeLine)
	{
		sQueryLinesRows = sQueryLinesRows + String(";\n");
		
		sQueryLines = "BEGIN \n";
		sQueryLines = sQueryLines + "SET NOCOUNT ON; \n";
		sQueryLines = sQueryLines + "DECLARE @AUSlotsLineResults_param  [dbo].[udt_AUSlotsLineResults]; \n";
		sQueryLines = sQueryLines + "INSERT @AUSlotsLineResults_param([gamenum],[linenumber],[payouttypeid],[basepayoutamount],[jackpot],[totalmultiplier],[totallinepayoutamount]) VALUES \n";
		
		sQueryLines = sQueryLines + sQueryLinesRows;
		
		sQueryLines = sQueryLines + "EXEC [dbo].[pub_AUSlotsCreateLineResultsAll] @AUSlotsLineResults = @AUSlotsLineResults_param;\n";
		sQueryLines = sQueryLines + "END";

		query = conn->query();		
		if (query)
		{
			query->define(sQueryLines);	
			ok = query->exec();
			if (!ok)
			{
				/**
				* Unable to execute query.
				*/
				ASSERT(0);
			}
			delete query;
		}
		else
		{
			/**
			* Couldn't get query
			*/
			ASSERT(0);
		}				
	}
	
	if (ok && bSomeNote)
	{
		sQueryNotesRows = sQueryNotesRows + String(";\n");
		
		sQueryNotes = "BEGIN \n";
		sQueryNotes = sQueryNotes + "SET NOCOUNT ON; \n";
		sQueryNotes = sQueryNotes + "DECLARE @AUSlotsLineResultsNotes_param  [dbo].[udt_AUSlotsLineResultsNotes]; \n";
		sQueryNotes = sQueryNotes + "INSERT @AUSlotsLineResultsNotes_param([gamenum],[linenumber],[noteid]) VALUES \n";
		
		sQueryNotes = sQueryNotes + sQueryNotesRows;
		
		sQueryNotes = sQueryNotes + "EXEC [dbo].[pub_AUSlotsCreateLineResultsNotesAll] @AUSlotsLineResultsNotes = @AUSlotsLineResultsNotes_param;\n";
		sQueryNotes = sQueryNotes + "END";

		query = conn->query();		
		if (query)
		{
			query->define(sQueryNotes);	
			ok = query->exec();
			if (!ok)
			{
				/**
				* Unable to execute query.
				*/
				ASSERT(0);
			}
			delete query;
		}
		else
		{
			/**
			* Couldn't get query
			*/
			ASSERT(0);
		}				
	}

	return ok;
}

bool8
SlotsSQL::saveScatters(SlotSpin *spin, ODBCConnection *conn)
{
	ODBCQuery* query;
	bool8 ok = true;

	// CSN-13472 - Rewrite additional AU Slots SPs to use a table-valued parameter
	// We have to create two scripts here:
	// 1) Create Line results (sQueryScatters)
	// 2) Create Line results notes (sQueryNotes)
	
	String sQueryScatters;
	String sQueryNotes;
		
	String sQueryScattersRows;
	String sQueryNotesRows;
	String sRow;

	bool8 bSomeScatter = false;
	bool8 bSomeNote = false;	

	for ( uint8 scatterIndex = 0; ok && scatterIndex < spin->getNumScatters(); scatterIndex++ )
	{
		SlotScatter* pScatter = spin->getScatter(scatterIndex);
	
		if (bSomeScatter)
			sQueryScattersRows = sQueryScattersRows + String(",");
				
		sRow.sprintf(TEXT("(%I64d,%u,%u,%u,CAST(%d/100.00 as MONEY),%u,%d,CAST(%d/100.00 as MONEY),%d)\n"), 
					spin->getGameNum(), pScatter->scatterid, pScatter->payouttypeid, pScatter->scatterposition, pScatter->basepayoutamount, pScatter->jackpot, pScatter->totalmultiplier, pScatter->totalscatterpayoutamount, pScatter->freespins); 
							
		sQueryScattersRows = sQueryScattersRows + sRow;
		bSomeScatter = true;
						
		for ( uint8 noteidx = 0; noteidx < pScatter->getNoteCount(); noteidx++ )
        {
			if (bSomeNote)
				sQueryNotesRows = sQueryNotesRows + String(",");
				
			sRow.sprintf(TEXT("(%I64d,%u,%u)\n"), spin->getGameNum(), pScatter->scatterid, pScatter->getNote(noteidx));

			sQueryNotesRows = sQueryNotesRows + sRow;
			bSomeNote = true;
		}
		
	}
	
	if (bSomeScatter)
	{
		sQueryScattersRows = sQueryScattersRows + String(";\n");
		
		sQueryScatters = "BEGIN \n";
		sQueryScatters = sQueryScatters + "SET NOCOUNT ON; \n";
		sQueryScatters = sQueryScatters + "DECLARE @AUSlotsScatterResults_param  [dbo].[udt_AUSlotsScatterResults]; \n";
		sQueryScatters = sQueryScatters + "INSERT @AUSlotsScatterResults_param([Gamenum],[ScatterID],[PayoutTypeID],[ScatterPositions],[BasePayoutAmount],[Jackpot],[totalmultiplier],[totalscatterpayoutamount],[freespins]) VALUES \n";
		
		sQueryScatters = sQueryScatters + sQueryScattersRows;
		
		sQueryScatters = sQueryScatters + "EXEC [dbo].[pub_AUSlotsCreateScatterResultsAll] @AUSlotsScatterResults = @AUSlotsScatterResults_param;\n";
		sQueryScatters = sQueryScatters + "END";

		query = conn->query();		
		if (query)
		{
			query->define(sQueryScatters);	
			ok = query->exec();
			if (!ok)
			{
				/**
				* Unable to execute query.
				*/
				ASSERT(0);
			}
			delete query;
		}
		else
		{
			/**
			* Couldn't get query
			*/
			ASSERT(0);
		}				
	}
	
	if (ok && bSomeNote)
	{
		sQueryNotesRows = sQueryNotesRows + String(";\n");
		
		sQueryNotes = "BEGIN \n";
		sQueryNotes = sQueryNotes + "SET NOCOUNT ON; \n";
		sQueryNotes = sQueryNotes + "DECLARE @AUSlotsScatterResultsNotes_param  [dbo].[udt_AUSlotsScatterResultsNotes]; \n";
		sQueryNotes = sQueryNotes + "INSERT @AUSlotsScatterResultsNotes_param([gamenum],[scatterid],[noteid]) VALUES \n";
		
		sQueryNotes = sQueryNotes + sQueryNotesRows;
		
		sQueryNotes = sQueryNotes + "EXEC [dbo].[pub_AUSlotsCreateScatterResultsNotesAll] @AUSlotsScatterResultsNotes = @AUSlotsScatterResultsNotes_param;\n";
		sQueryNotes = sQueryNotes + "END";

		query = conn->query();		
		if (query)
		{
			query->define(sQueryNotes);	
			ok = query->exec();
			if (!ok)
			{
				/**
				* Unable to execute query.
				*/
				ASSERT(0);
			}
			delete query;
		}
		else
		{
			/**
			* Couldn't get query
			*/
			ASSERT(0);
		}				
	}

	return ok;
}

int32 
SlotsSQL::saveBonusGames(SlotGuts *guts)
{
	return saveBonusGames( guts, autoDeleteConn( getConn() ).get() );
}

int32 
SlotsSQL::saveBonusGames(SlotGuts *guts, ODBCConnection* conn)
{
    SlotSpin *spin;
	bool8 ok = true;

    spin = guts->getSlotSpin();

    for ( uint8 bonusGameIndex = 0; ok && bonusGameIndex < spin->getNumBonusGames(); bonusGameIndex++ )
    {
		BonusGame* pBonusGame = spin->getBonusGame( bonusGameIndex );

		if ( !pBonusGame->bSaved )
		{
			ok = createBonusGame( guts,
								  spin->getGameNum(),
								  pBonusGame->bonusgametype,
								  pBonusGame->bonusgameindex,
								  pBonusGame->basepayoutamount,
								  pBonusGame->totalmultiplier,
								  pBonusGame->totalbonuspayoutamount,
								  pBonusGame->freespins, conn );

			if ( ok )
			{
                for ( uint8 noteidx = 0; noteidx < pBonusGame->getNoteCount(); noteidx++ )
                {
                    ok = createBonusResultNote( spin->getGameNum(), pBonusGame->bonusgameindex, pBonusGame->getNote(noteidx), conn);

                    if ( !ok )
                    {
                        break;
                    }
                }

                if (ok)
                {
					pBonusGame->bSaved = true;
                }
				else
				{
					break;
				}
			}
		}
    }

    if ( !ok )
    {
        /**
         * unable to save bonus games
         */
        ASSERT(0);
    }

	return ok ? NoError : ExecFailed;
}

int32 
SlotsSQL::saveGame(int32 casinoId, SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
    int64 gameNum;

	conn = getConn();
	if ( conn )
    {
    	query = conn->query();
    	if (query)
    	{
            SlotSpin *spin = guts->getSlotSpin();

            /** 
             * Only save a spin if it has yet to be saved.
             */
            if ( spin->getGameNum() == 0 )
            {

                query->define("exec pub_AUSlotsCreateGame ");
                query->addParam(casinoId);
                query->addParam(guts->getInfo()->pid);
                query->addParam(guts->getMachId(), ODBCQuery::BINARY);
                query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);
                query->addParam(spin->getGameModeId());
                query->addParam((bool8)(guts->isForMoney() != 0));
                query->addParam(guts->getInfo()->sessionId, ODBCQuery::NOQUOTES);
                query->addParam((int32) (guts->getInfo()->forMoney ? guts->getInfo()->compFactor : 0), ODBCQuery::NOTMONEY);
				//query->addParam((int32)(spin->getBet() * spin->getSpinLineCount() * guts->getInfo()->betperline), ODBCQuery::MONEY);
				//query->addParam(spin->getSpinLineCount());
				// cgc: el luchador
				query->addParam((int32)(spin->getBet() * guts->getNumLinesBet() * guts->getInfo()->betperline), ODBCQuery::MONEY);
				query->addParam(guts->getNumLinesBet());
                query->addParam(spin->getMultibankBet(), ODBCQuery::MILLIMONEY);
                query->addParam(guts->getGutsId());
                query->addParam(spin->getBonusGameType());
                query->addParam(guts->getReferenceGameNum());
                query->addParam(guts->isMalfunction());
                query->addParam((int32)guts->getInfo()->betperline);
                query->addParam((bool8)spin->getAutoplay());
                query->addParam(guts->shouldSaveGameData());

                if (query->exec())
                {
                    query->getRow();
    
                    ok = query->getData(1, &guts->getInfo()->balance, ODBCQuery::MONEY);
                     
                    if ( ok )
                    {
                        ok = query->getData(3, &gameNum); 
                    }
                    else
                    {
                        /**
                         * unable to get balance
                         */
                        ASSERT(0);
                    }
    
                    if ( ok )
                    {
                        spin->setGameNum(gameNum);
#ifdef USE_MISSINGGAMENUMS
						if (missinggamenums)
							missinggamenums->setGameNum(gameNum);
#endif
					}
                    else
                    {
                        /**
                         * unable to get gamenum
                         */
                        ASSERT(0);
                    }

                    if ( spin->getBet() > 0 )
                    {
						if ( guts->shouldSaveGameData() )
                        {
                            guts->setReferenceGameNum(gameNum);
						    guts->getFeature()->setGameNum(gameNum);
                        }
                        else
                        {
							// We need to set the game number to something other than 0 so that the
							// rest of the code will work correctly.  This should never be saved to
							// the database since we are not saving game data, so it really doesn't
							// matter what it is set to as long as it is not 0.
                            guts->setReferenceGameNum(-1);
                            guts->getFeature()->setGameNum(-1);
                        }
                    }
                }
                else
                {
                    /**
                     * Bad exec of create game.
                     */
                    ASSERT(0);
                }
            }
        	delete query;
        }
        else
        {
            /**
             * Bad query.
             */
            ASSERT(0);
        }
	    delete conn;
    }
    else
    {
        /**
         * Bad conn.
         */
        ASSERT(0);
    }


	return ok ? NoError : ExecFailed;

}






/**
 * @brief get the reels from the database.
 * 
 */
bool8
SlotsSQL::getGutsReels(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{


        query->define("exec pub_AUSlotsGetGutsReels ");
        query->addParam(guts->getGutsId());
    
        if (query->exec())
        {
            uint8 reelid;
            uint8 position;
            uint8 iconid;
            uint8 gamemodeid;
            int64 weight;
            char iconName[64];
    
            guts->clearWheelhouse();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, &gamemodeid);
                if ( ok )
                {
                    ok = query->getData(column++, &reelid);
                }
                else
                {
                    /**
                     * Unable to get gamemodeid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &position);
                }
                else
                {
                    /**
                     * Unable to get reelid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &iconid);
                }
                else
                {
                    /**
                     * Unable to get position.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &weight);
                }
                else
                {
                    /**
                     * Unable to get iconid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, iconName, sizeof(iconName));
                }
                else
                {
                    /**
                     * Unable to get weight.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    guts->addIcon(gamemodeid, reelid, iconid, position, weight, iconName);
                }
                else
                {
                    /**
                     * Unable to get icon name.
                     */
                    ASSERT(0);
                }

            }
        }
        delete query;
    }
	delete conn;

    return ok;
}

/**
 * @brief get the paylines from the database.
 * 
 */
bool8
SlotsSQL::getGutsPaylines(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{


        query->define("exec pub_AUSlotsGetGutsPaylines ");
        query->addParam(guts->getGutsId());
    
        if (query->exec())
        {
            uint8 paylineid;
            uint8 reelid;
            uint8 wheelposition;
    
            guts->clearPaylines();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, &paylineid);

                if ( ok )
                {
                    ok = query->getData(column++, &reelid);
                }
                else
                {
                    /**
                     * Invalid paylineid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &wheelposition);
                }
                else
                {
                    /**
                     * Invalid reelid.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    guts->addPayline(paylineid, reelid, wheelposition);
                }
                else
                {
                    /**
                     * Invalid wheel position.
                     */
                    ASSERT(0);
                }
            }
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}

/**
 * @brief get the payouts from the database.
 * 
 */
bool8
SlotsSQL::getGutsPayouts(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_AUSlotsGetGutsPayouts ");
        query->addParam(guts->getGutsId());
    
        if (query->exec())
        {
           uint8    payoutTypeId;
           char     payoutName[64];
           int32    payoutAmount;
    
            guts->clearPayTable();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, &payoutTypeId);

                if ( ok )
                {
                    ok = query->getData(column++, payoutName, sizeof(payoutName));
                }
                else
                {
                    /**
                     * Unable to get payout type id.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &payoutAmount);
                }
                else
                {
                    /**
                     * Unable to get payout name.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    guts->addPayout(payoutTypeId, payoutName, payoutAmount);
                }
                else
                {
                    /**
                     * Unable to get payout amount.
                     */
                    ASSERT(0);
                }
            }
        }
        delete query;
    }
    else
    {
        /**
         * Invalid query object.
         */
        ASSERT(0);
    }
    delete conn;

    return ok;
}



/**
 * @brief get the guts from the database.
 * 
 */
int32 
SlotsSQL::getGuts(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        /**
         * Get the gutsid.
         */
		query->define("exec pub_AUSlotsGetOptions ");
        query->addParam(guts->getMachId());
        query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);

		if (query->exec())
		{
            int32 gutsId;
            int32 jackpotId;
			int32 jackpotHitOdds;
            bool8 progressive;

            /**
             * Only 1 row, no need for a loop.
             */
			query->getRow();  

            int column = 1;
            ok = query->getData(column++, &gutsId);
            if ( ok )
            {
                ok = query->getData(column++, &jackpotId);
            }
            else
            {
                /**
                 * Unable to get gutsid.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                ok = query->getData(column++, &jackpotHitOdds);
            }
            else
            {
                /**
                 * Unable to get jackpotid.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                ok = query->getData(column++, &progressive);
            }
            else
            {
                /**
                 * Unable to get jackpothitodds.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
				// Skip cross casino progressive column
				column++;
            }
            else
            {
                /**
                 * Unable to get  progressive.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                guts->setGutsId(gutsId);
                guts->setJackpotId(jackpotId);
				guts->setJackpotHitOdds(jackpotHitOdds);
                guts->setProgressive(progressive);
            }
            else
            {
                /**
                 * Unable to get cross casino progressive.
                 */
                ASSERT(0);
            }

            if ( ok )
            {
                ok = this->getGutsPayouts(guts);
            }

            if ( ok )
            {
                ok = this->getGutsReels(guts);
            }

            if ( ok )
            {
                ok = this->getGutsPaylines(guts);
            }

            if ( ok )
            {
                ok = this->getGutsDenominations(guts);
            }

			if ( ok )
			{
				ok = this->getProbabilityTables(guts);
			}
        }

		delete query;
	}
	delete conn;

	return ok ? NoError : ExecFailed;
}


int32
SlotsSQL::getSavedGame(SlotGuts* guts, int32 *gutsid, int64 *gamenum,uint8* bonusgamenum, bool8 *malfunctioned, bool8 *completed, int32* betperline) 
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_AUSlotsGetSavedGame ");
        query->addParam(guts->getMachId(), ODBCQuery::BINARY);
        query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);
		query->addParam(guts->getInfo()->pid);
		query->addParam((bool8)(guts->isForMoney() != 0));

		if (query->exec())
        {
  
                /**
                 * Only 1 row, no need for a loop.
                 */

                int column = 1;

				ok = (query->getRow() && query->getData(column++,gamenum));  

				//gamenum
				if ( ok )
                {
                    ok = query->getData(column++, gutsid);
                }
                else
                {
                    /**
                     * Unable to get gamenum, but that's okay
                     */
                    *gamenum = -1;
                }
				if ( ok )
                {
                    ok = query->getData(column++, bonusgamenum);
                }
                else
                {
                    /**
                     * Unable to get gutsid, but that's okay
                     */
                    *gamenum = -1;
                }
				if( ok)
				{
					ok = query->getData(column++,malfunctioned);
				}
                else
                {
                    /**
                     * Unable to get bonusgamenum, but that's okay
                     */
                    *gamenum = -1;
                }

				if( ok)
				{
					ok = query->getData(column++,completed);
				}
                else
                {
                    /**
                     * Unable to get malfunctioned, but that's okay
                     */
                    *gamenum = -1;
                }

				if( ok)
				{
					ok = query->getData(column++,betperline);
				}
                else
                {
                    /**
                     * Unable to get completed, but that's okay
                     */
                    *gamenum = -1;
                }

				if(!ok)
				{
                    /**
                     * Unable to get betperline,, but that's okay
                     */
                    *gamenum = -1;
				}

            }
            else
            {
                /**
                 * Unable to execute query.
                 */
                *gamenum = -1;
            }
	} // if query
	delete query;
	delete conn;
	if(ok)
	{
		return SlotsSQL::NoError;
	}
	else
	{
		return SlotsSQL::ExecFailed;
	}
}


bool8
SlotsSQL::loadGameDataIntoSpin(int64 gamenum, SlotGuts* guts, SlotSpin* spin)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;
	int32 bet = 0;
	uint8 linesbet = 0;
	int32 totalPayout = 0;
    int32 betperline = 0;

	conn = getConn();
	if (!conn)
		return NoConnection;

	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_AUSlotsGetGame ");
        query->addParam(gamenum);
		if (query->exec())
		{
            /**
             * Only 1 row, no need for a loop.
             */
			query->getRow();  

			int column = 1;
			ok = query->getData(column++, &bet,ODBCQuery::MONEY);
			if(ok)
			{
				ok = query->getData(column++, &linesbet);
			}
			else
			{
				ASSERT(0); //Problem with bet
			}
			if(ok)
			{
				ok = query->getData(column++, &totalPayout,ODBCQuery::MONEY);
			}
			else
			{
				ASSERT(0); //Problem with the lines bet
			}
			if(ok)
			{
				ok = query->getData(column++, &betperline);
			}
			else
			{
				ASSERT(0); //Problem with the total payout
			}
			if(!ok)
			{
				ASSERT(0); //Problem with bet per line
			}
		}//query exec
	} //conn->query
	delete query;	
	delete conn;
	if(ok)
	{
        guts->getInfo()->betperline = betperline;
        spin->setGameNum(gamenum);
    	spin->setBet((bet/linesbet)/guts->getInfo()->betperline);
		spin->setBonusGameType((guts->getSubGame())->getDataAt(0));

        ok = loadWinsDataIntoSpin(spin, linesbet);
        ok = loadScatterResultsDataIntoSpin(spin);
		ok = loadBonusResultsDataIntoSpin(spin);
		ok = loadStopsIntoSpin(spin,guts->getReelCount());
	}

	if(ok)
	{
		return SlotsSQL::NoError;
	}
	else
	{
		return SlotsSQL::ExecFailed;
	}
}

bool8
SlotsSQL::loadWinsDataIntoSpin(SlotSpin* spin, uint8 ucLinesBet)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	conn = getConn();
	
	uint8 lineNumber,payoutType;
	int32 basepayoutamount;
    int32 totalmultiplier;
    int32 totalpayoutamount;

    uint8 ucLastLine=0;

	bool8 jackpot;
	
	if (!conn)
		return NoConnection;
	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_AUSlotsGetWins ");
        query->addParam(spin->getGameNum());
		if (query->exec())
		{
			while ( ok && query->getRow() )
			{
				int column = 1;
				ok = query->getData(column++, &lineNumber);
				if(ok)
				{
					ok = query->getData(column++, &payoutType);
				}
				else
				{
					ASSERT(0); //Problem with lineNumber
				}
				if(ok)
				{
					ok = query->getData(column++, &basepayoutamount,ODBCQuery::MONEY);
				}
				else
				{
					ASSERT(0); //Problem with the payout type
				}
				if(ok)
				{
					ok = query->getData(column++, &totalmultiplier);
				}
				else
				{
					ASSERT(0); //Problem with the base payout amount
				}
				if(ok)
				{
					ok = query->getData(column++, &totalpayoutamount,ODBCQuery::MONEY);
				}
				else
				{
					ASSERT(0); //Problem with the multiplier
				}
				if(ok)
				{
					ok = query->getData(column++,&jackpot);
				}
				else
				{
					ASSERT(0); //Problem with the total payout amount
				}
				if(ok)
				{
                    // kharmon.  05-03-07.  #19354.  We no longer save "loser" lines, since all losing lines are
                    // exactly the same.  Now we only save the winning lines to database, and not having
                    // a record in the database indicates that the line was a loser.  BUT, we still need
                    // these loser lines in the "spin" data structure for this restored game, so we just
                    // add them back in here. This code fills in the missing lines between the last win 
                    // line and this current win line as losses.
                    if(lineNumber>(ucLastLine+1))
                    {
                        for(uint8 ucCount=ucLastLine+1;ucCount<lineNumber;++ucCount)
                        {
                            spin->addLine(ucCount);
                        }
                    }

                    ucLastLine = lineNumber;

					spin->addLine(lineNumber);
					spin->setPayoutAmount(lineNumber,basepayoutamount, totalmultiplier, totalpayoutamount, jackpot,payoutType);
					spin->setSpinSaved(true);
				}
				else
				{
					ASSERT(0); //Problem with the jackpot flag
				}

			}//while getRow()
		}//if (query->exec())
	} //if(query)
	delete query;
	delete conn;

    // kharon.  05-03-07.  #19354.  Now fill in any remaining lines as losses.
    if(ok && ucLinesBet > ucLastLine)
    {
        uint8 ucMaxLine = ucLinesBet+1;
        for(uint8 ucCount=ucLastLine+1;ucCount<ucMaxLine;++ucCount)
        {
            spin->addLine(ucCount);
        }
    }


	return ok;
}

bool8
SlotsSQL::loadScatterResultsDataIntoSpin(SlotSpin* spin)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	conn = getConn();
	
    int32 scatterpos = 0; 
    uint8 payouttypeid = 0; 
    int32 basepayoutamount = 0;
    int32 totalmultiplier = 0;
    int32 totalscatterpayoutamount = 0;
    int32 freespins = 0;
    bool8 jackpot = false;
	
	if (!conn)
		return NoConnection;
	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_AUSlotsGetScatterResults ");
        query->addParam(spin->getGameNum());
		if (query->exec())
		{
			while ( ok && query->getRow() )
			{
				int column = 1;

				ok = query->getData(column++, &scatterpos);

                if (ok)
				{
					ok = query->getData(column++, &payouttypeid);
				}
				
                if (ok)
				{
					ok = query->getData(column++, &basepayoutamount,ODBCQuery::MONEY);
				}
				
                if (ok)
				{
					ok = query->getData(column++, &totalmultiplier);
				}

                if (ok)
				{
					ok = query->getData(column++, &totalscatterpayoutamount,ODBCQuery::MONEY);
				}

                if (ok)
				{
					ok = query->getData(column++,&jackpot);
				}
				
                if (ok)
				{
					ok = query->getData(column++, &freespins);
				}
				
                if (ok)
				{
                    spin->addScatter(scatterpos, basepayoutamount, totalmultiplier, jackpot, payouttypeid, freespins );
				}
                else
                {   
                    // Use column to determine which getData failed.
                    ASSERT(false);
                }

			}//while getRow()
		}//if (query->exec())
	} //if(query)
	delete query;
	delete conn;
	return ok;
}


bool8
SlotsSQL::loadBonusResultsDataIntoSpin(SlotSpin* spin)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	conn = getConn();
	
    uint8 gametype = 0; 
    uint8 gameindex = 0; 
    int32 basepayoutamount = 0;
    int32 totalmultiplier = 0;
    int32 totalbonuspayout = 0;
    int32 freespins = 0;
	
	if (!conn)
		return NoConnection;
	   
	query = conn->query();
	if (query)
	{
		query->define("exec pub_AUSlotsGetBonusGame ");
        query->addParam(spin->getGameNum());
		if (query->exec())
		{
			while ( ok && query->getRow() )
			{
				int column = 1;

				ok = query->getData(column++, &gametype);

                if (ok)
				{
					ok = query->getData(column++, &gameindex);
				}
				
                if (ok)
				{
					ok = query->getData(column++, &basepayoutamount,ODBCQuery::MONEY);
				}
				
                if (ok)
				{
					ok = query->getData(column++, &totalmultiplier);
				}

                if (ok)
				{
					ok = query->getData(column++, &totalbonuspayout,ODBCQuery::MONEY);
				}

                if (ok)
				{
					ok = query->getData(column++, &freespins);
				}
				
                if (ok)
				{
                    spin->addBonusGame(gametype, gameindex,basepayoutamount,totalmultiplier,totalbonuspayout,freespins,0,true);
				}
                else
                {   
                    // Use column to determine which getData failed.
                    ASSERT(false);
                }

			}//while getRow()
		}//if (query->exec())
	} //if(query)
	delete query;
	delete conn;
	return ok;
}


bool8
SlotsSQL::loadStopsIntoSpin(SlotSpin* spin, uint8 numStops)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	conn = getConn();

	
	if (!conn)
		return NoConnection;
	   
	query = conn->query();
	if (query)
	{
		vector<uint8> stops( numStops );

		query->define("exec pub_AUSlotsGetWheels ");
		query->addParam(spin->getGameNum());
		uint8 stopNum = (uint8)-1;
		if (query->exec())
		{
			while ( ok && query->getRow() )
			{
				stopNum++;
				if(stopNum>=numStops)
				{
					ASSERT(0); //Got more stops than we expected
				}
				ok = query->getData(2, &stops[stopNum]);
				if(!ok)
				{
					ASSERT(0); //Problem with lineNumber
				}

			}//while getRow

		}//if (query->exec())
		
		spin->setStops(stopNum+1,&stops[0]);
	} //if(query)

	delete query;
	delete conn;
	return ok;
}

/**
 * @brief load a probability table from the database.
 * 
 */
bool8
SlotsSQL::loadProbabilityTable( SlotGuts *guts, int32 nTableID )
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_AUSlotsGetProbabilityTable ");
        query->addParam(guts->getGutsId());
		query->addParam(nTableID);
    
        if (query->exec())
        {
			uint32 nMaxWeightForValue;
			int32 nValue;
    
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, &nMaxWeightForValue);

                if ( ok )
                {
                    ok = query->getData(column++, &nValue);
                }
                else
                {
                    /**
                     * Invalid weight.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    guts->addProbabilityTableEntry( nTableID, nMaxWeightForValue, nValue );
                }
                else
                {
                    /**
                     * Invalid value.
                     */
                    ASSERT(0);
                }
            }
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}

bool8
SlotsSQL::getProbabilityTables( SlotGuts *guts )
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_AUSlotsGetProbabilityTableIDs ");
        query->addParam(guts->getGutsId());
    
        if (query->exec())
        {
			int32 nTableID;

			// There might not be any probability tables for this game.
			ok = true;
    
			guts->clearProbabilityTables();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, &nTableID);

                if ( ok )
                {
                    guts->addProbabilityTable( nTableID );

					loadProbabilityTable( guts, nTableID );
                }
                else
                {
                    /**
                     * Invalid ID.
                     */
                    ASSERT(0);
                }
            }
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}

bool8
SlotsSQL::completeGame(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = true;
	int32 throwawayComp;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        SlotSpin *spin = guts->getSlotSpin();

        int32 totalWin = 0;
        int32 jackpotWin = 0;

        getWinAmounts( spin, totalWin, jackpotWin );

        query->define("exec pub_AUSlotsCompleteGame ");

        query->addParam(ServerOpts::casinoId);
        query->addParam(guts->getInfo()->pid);
        query->addParam(guts->getMachId(), ODBCQuery::BINARY);
        query->addParam((int32) guts->getInfo()->machineSubID, ODBCQuery::NOTMONEY);
        query->addParam((bool8)(guts->isForMoney() != 0));
        query->addParam(guts->getInfo()->sessionId, ODBCQuery::NOQUOTES);
        //query->addParam((int32)(spin->getBet() * spin->getSpinLineCount() * guts->getInfo()->betperline), ODBCQuery::MONEY);
		// cgc: el luchador
		query->addParam((int32)(spin->getBet() * guts->getNumLinesBet() * guts->getInfo()->betperline), ODBCQuery::MONEY);
        query->addParam((int32)spin->getMultibankPayout(), ODBCQuery::MILLIMONEY);
		query->addParam(spin->getGameNum());
		query->addParam(guts->getGutsId());
        query->addParam(totalWin, ODBCQuery::MONEY);
        query->addParam(jackpotWin, ODBCQuery::MONEY);
        query->addParam(guts->shouldSaveGameData());

        if (query->exec())
        {
            ok = true;

            /**
             * Only 1 row, no need for a loop.
             */
            query->getRow();  

            int column = 1;

            ok = query->getData(column++, &guts->getInfo()->balance, ODBCQuery::MONEY);

            if ( ok )
            {
                ok = query->getData(column++, &throwawayComp);
            }
            else
            {
                /**
                 * Unable to get balance
                 */
                ASSERT(0);
            }

            if ( !ok )
            {
                /**
                 * Unable to get comps
                 */
                ASSERT(0);
            }
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}


		
int32
SlotsSQL::createSavedGame(const PID& pid, uint8 machid, int16 machsubid, bool8 forMoney, int64 gamenum, int32 gutsid, uint8 bonusGameNum)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if ( conn )
    {
    	query = conn->query();
    	if (query)
    	{
            query->define("exec pub_SlotsCreateSavedGame ");
            query->addParam(pid);
            query->addParam(machid, ODBCQuery::BINARY);
            query->addParam((int32) machsubid, ODBCQuery::NOTMONEY);
            query->addParam((bool8) forMoney);
            query->addParam(gamenum, ODBCQuery::NOTMONEY);
            query->addParam(gutsid);
            query->addParam(bonusGameNum);

            if (query->exec())
            {
                ok = true;
            }
            else
            {
                /**
                 * Unable to execute query.
                 */
                ASSERT(0);
            }
            delete query;
        }
	    delete conn;
    }
    else
    {
        /**
         * Invalid connection.
         */
        ASSERT(0);
    }


	return ok ? NoError : ExecFailed;
}



/**
 * @brief get the denominations from the database.
 * 
 */
bool8
SlotsSQL::getGutsDenominations(SlotGuts *guts)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

    localCurrency lc;
    ok = GetLocale(&lc);

    if (!ok)
    {
        return ok;
    }

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
        query->define("exec pub_GetGameDenominations ");
        query->addParam((int32)GAMEID);
        query->addParam(guts->getMachId());
        query->addParam(lc.int_curr_symbol);
    
        if (query->exec())
        {
            uint16  machineSubId;
            uint16  creditValue;
            bool8   isDefault;
    
            guts->clearDenominations();
            while (query->getRow())
            {
                int column = 1;
                ok = query->getData(column++, (int16*)&machineSubId);

                if ( ok )
                {
                    ok = query->getData(column++, (int16*)&creditValue);
                }
                else
                {
                    /**
                     * Invalid subMachineId.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    ok = query->getData(column++, &isDefault);
                }
                else
                {
                    /**
                     * Invalid creditValue.
                     */
                    ASSERT(0);
                }

                if ( ok )
                {
                    guts->addDenomination(machineSubId, creditValue, isDefault);
                }
                else
                {
                    /**
                     * Invalid isDefault.
                     */
                    ASSERT(0);
                }
            }
        }
        else
        {
            /**
             * Unable to execute query.
             */
            ASSERT(0);
        }
        delete query;
    }
	delete conn;

    return ok;
}

bool8 
SlotsSQL::GetLocale( localCurrency *localCurr )
{
	return (getLocale(localCurr) == NoError);
}

void
SlotsSQL::getWinAmounts( SlotSpin* spin, int32& totalWin, int32&jackpotWin )
{
    totalWin = 0;
    jackpotWin = 0;

    for ( uint8 bonusGameIndex = 0; bonusGameIndex < spin->getNumBonusGames(); bonusGameIndex++ )
    {
		BonusGame* pBonusGame = spin->getBonusGame( bonusGameIndex );
        totalWin += pBonusGame->totalbonuspayoutamount;
    }

    for ( uint8 lineidx = 0; lineidx < spin->getSpinLineCount(); lineidx++ )
    {
        const SpinLine *spinLine = spin->getSpinLineAt(lineidx);
        totalWin += spinLine->totallinepayoutamount;
    }

    for ( uint8 scatterIndex = 0; scatterIndex < spin->getNumScatters(); scatterIndex++ )
    {
        SlotScatter* pScatter = spin->getScatter(scatterIndex);

        totalWin += pScatter->totalscatterpayoutamount;

        if ( pScatter->jackpot )
        {
            jackpotWin += pScatter->totalscatterpayoutamount;
        }
    }
}

bool8
SlotsSQL::getDebugSpins(int32 gutsId, DebugStops& stops, int32& numRecords,PID pid)
{
	ODBCConnection* conn;
	ODBCQuery* query;
	bool8 ok = false;

	conn = getConn();
	if (!conn)
		return NoConnection;

	query = conn->query();
	if (query)
	{
		query->define("exec pub_auDebugGetFiveReelSpins ");
		query->addParam(gutsId);
        query->addParam(pid);

		if (query->exec())
		{
			int32 i=0;
			while (query->getRow())
			{
				FiveReelDebugStops stopVals( 5 );

				ok = (query->getData(3, &stopVals[0]) && 
					query->getData(4, &stopVals[1]) && 
					query->getData(5, &stopVals[2]) && 
					query->getData(6, &stopVals[3]) && 
					query->getData(7, &stopVals[4]));

				if ( !ok )
				{
					/**
					* Unable to get Name.
					*/
					ok = false;
					numRecords = 0;
					ASSERT(0);
					break;
				}
				else
				{
					stops.push_back(stopVals);
					numRecords++;
				}
				++i;
			}
		}
		delete query;
	}
	delete conn;

	return ok;
}

